package com.medusa.aps.business.modules.basic.model;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharPool;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.annotation.JSONField;
import com.medusa.aps.business.model.constant.CommonConstants;
import com.medusa.aps.business.util.DateTimeUtils;
import com.medusa.aps.business.global.model.exception.GlobalException;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.time.LocalTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 时段
 *
 * @author 张治保
 * @since 2023-10-07
 */
@Getter
@Setter
@Accessors(chain = true)
@Schema(title = "时段", description = "结束时间需大于开始时间，并且与其他时段不能有交集")
public class WorkPeriod implements Comparable<WorkPeriod>, Serializable {


    /**
     * 时段开始时间
     */
    @NotNull(message = "时段开始时间不能为空")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段开始时间", type = "string", example = "09:00")
    private LocalTime start;

    /**
     * 时段结束时间
     */
    @NotNull(message = "时段结束时间不能为空")
    @JSONField(format = DateTimeUtils.HOUR_MINUTE_PATTERN)
    @Schema(description = "时段结束时间", type = "string", example = "18:00")
    private LocalTime end;

    /**
     * 时段字符串转换为对象
     *
     * @param timeStr 时段字符串，格式为：09:00-18:00
     * @return 时段对象
     */
    public static WorkPeriod fromStr(String timeStr) {
        if (StrUtil.isEmpty(timeStr)) {
            throw new IllegalArgumentException("时段字符串不能为空");
        }
        String[] timeArr = StrUtil.splitToArray(timeStr, CharPool.DASHED);
        return new WorkPeriod()
                .setStart(LocalTime.parse(timeArr[0], DateTimeUtils.HOUR_MINUTE_FORMATTER))
                .setEnd(LocalTime.parse(timeArr[1], DateTimeUtils.HOUR_MINUTE_FORMATTER));
    }

    /**
     * 工作时段列表转换为字符串
     *
     * @return 工作时段字符串
     */
    public static String periods2Str(List<WorkPeriod> periods) {
        if (CollUtil.isEmpty(periods)) {
            throw new IllegalArgumentException("工作时段列表不能为空");
        }
        return periods.stream()
                .sorted()
                .map(WorkPeriod::toString)
                .collect(Collectors.joining(CommonConstants.SPLIT_SYMBOL));
    }

    /**
     * 工作时段字符串转换为列表
     *
     * @param timeStr 工作时段字符串
     * @return 工作时段列表 09:00-18:00;09:00-18:00
     */
    public static List<WorkPeriod> str2Periods(String timeStr) {
        if (StrUtil.isEmpty(timeStr)) {
            throw new IllegalArgumentException("工作时段字符串不能为空");
        }
        return StrUtil.splitTrim(timeStr, CommonConstants.SPLIT_SYMBOL)
                .stream()
                .map(WorkPeriod::fromStr)
                .sorted()
                .toList();
    }


    /**
     * 校验 时段开始时间不能大于结束时间
     */
    public void valid() {
        if (start == null || end == null) {
            throw new GlobalException("时段开始时间和结束时间不能为空");
        }
        if (start.equals(end)) {
            throw new GlobalException("时段开始时间和结束时间不能相同");
        }
        if (start.isAfter(end)) {
            throw new GlobalException("时段开始时间不能大于结束时间");
        }
    }

    /**
     * 校验 时段是否有交集
     *
     * @param other 时段
     * @return true 有交集
     */
    public boolean isOverlap(WorkPeriod other) {
        return start.isBefore(other.end) && end.isAfter(other.start);
    }

    /**
     * 时段对象转换为字符串 09:00-18:00
     *
     * @return 时段字符串
     */
    @Override
    public String toString() {
        return start.format(DateTimeUtils.HOUR_MINUTE_FORMATTER) + StrPool.DASHED + end.format(DateTimeUtils.HOUR_MINUTE_FORMATTER);
    }

    /**
     * 根据开始时间排序 从小到大
     *
     * @param o the object to be compared.
     * @return a negative integer, zero, or a positive integer as this object is less than, equal to,
     */
    @Override
    public int compareTo(WorkPeriod o) {
        return this.start.compareTo(o.start);
    }
}